package com.study.api;

import com.study.exception.BizException;

/**
 * @description：雪花算法实现全局id
 * @author：李军荣
 * @date: 2020/12/29 17:36
 */
public class SnowFlaskGenerator {

    //机房id最大位数
    private long roomIdBit = 5l;

    //机器id最大位数
    private long workIdBit = 5l;

    //序号id最大位数
    private long numberIdBit = 12l;

    //工作id移动位数
    private long workMoveBit = numberIdBit;
    //机房id移动位数
    private long roomMoveBit = numberIdBit+workIdBit;
    //时间戳移动位数
    private long timeMoveBit = numberIdBit+workIdBit+roomIdBit;

    private long  roomId;
    private long  workId;
    private long  numberId;

    //机房id最大值
    private long maxRoomId = -1 ^ (-1 << roomIdBit);

    //机器id最大值
    private long maxWorkId = -1 ^ (-1 << workIdBit);

    //序号id最大值
    private long maxNumberId = -1 ^ (-1 << numberIdBit);

    //最后生成的时间戳
    private long lastTimeStamp;

    //开始时间戳
    private long startTimeStamp = 1609236114902l;


    /**
     * @Title: SnowFlaskGenerator
     * @Description:
     * @author 李军荣
     * @param roomId 
     * @param workId
     * @date 2021/2/3 15:28
     * @return
     */
    public SnowFlaskGenerator(long roomId, long workId) {
        if(roomId > maxRoomId){
            throw new BizException("机房id值已超出最大限制");
        }

        if(workId > maxWorkId){
            throw new BizException("机器id值已超出最大限制");
        }
        this.roomId = roomId;
        this.workId = workId;
    }

    public SnowFlaskGenerator(long roomId, long workId, long numberId) {
        if(roomId > maxRoomId){
            throw new BizException("机房id值已超出最大限制");
        }

        if(workId > maxWorkId){
            throw new BizException("机器id值已超出最大限制");
        }

        this.numberId = numberId;
        this.roomId = roomId;
        this.workId = workId;
    }


    public synchronized long generotorId(){
        long currentStamp = System.currentTimeMillis();
        if(lastTimeStamp == 0){
            lastTimeStamp = currentStamp;
        }

        if(currentStamp < lastTimeStamp){
            throw new BizException("当前系统时间戳回退了");
        }


        if(lastTimeStamp ==  currentStamp){
             if(((numberId+1) & maxNumberId) == 0){
                 currentStamp = createNextTimeStamp(currentStamp);
                 numberId = currentStamp & 1;
             }else{
                 numberId++;
             }
        }else{
            numberId = currentStamp & 1;
        }

        return  ((currentStamp-startTimeStamp)<<timeMoveBit) | (roomId << roomMoveBit) | (workId << workMoveBit) | numberId;
    }

    private long createNextTimeStamp(long lastTimeStamp) {
        long currentStamp = System.currentTimeMillis();
        while (currentStamp <= lastTimeStamp){
            currentStamp = System.currentTimeMillis();
        }
        return currentStamp;
    }

    public static void main(String[] args) {
        SnowFlaskGenerator snowFlaskGenerator = new SnowFlaskGenerator(1,1);
        for(int i = 0; i < 10; i++){
            System.out.println(snowFlaskGenerator.generotorId());
        }
    }

}
